<?php
/**
 * Form元素控件
 * 
 * 控件的属性有：
 * - exec <bool> - 是否将value值当作一个表单时执行，默认为true
 * - value_get <mixed> - 以GET方式访问时的值
 * - value_post <mixed> - 以POST方式访问时的值
 * - required <boolean> - 是否必须有值
 * - error.render <boolean> - 是否绘制错误信息
 * - error.required <string> - required条件检查失败时的提示信息
 * - layout.* <array> - 布局
 * - redisplay <boolean> 是否重新显示控件的值，默认为true
 * 
 * 发生错误时(如校验失败)自动加入class="ui_field_error"，如果原来已经有class，那么将保留原来的值
 *
 * @since 1.1.0
 * @package if
 * @subpackage module.ui
 */
abstract class UIFormElement extends UIControl {
	protected $reserveAttrs = array( "validate", "exec", "value_get", "value_post", "layout", "required", "error", "redisplay" );
	private static $indexes = array();
	private $errors = array();
	private $validators = array();
	protected $required = false;
	protected $groupValue = false;
	private $indexedName;
	/**
	 * 所在表单
	 *
	 * @var UIForm
	 */
	private $form;
	
	function addChild(UIControl $child) {
		parent::addChild($child);
		if (if_is_instance_of($child, "UIValidator")) {
			$child->parse();
			$this->validators[$child->id()] = array(
				"rule" => $child->rule(),
				"params" => $child->params(),
				"message" => $child->message()
			);
		}
	}
	
	/**
	 * 设置一组校验规则
	 * 
	 * 每一个校验规则都由
	 * - rule <string> 规则名
	 * - params <array> 参数
	 * - message <string> 消息
	 * 组成
	 *
	 * @param array $validators 校验规则
	 * @since 1.1.0
	 */
	function setValidators(array $validators) {
		$this->validators = $validators;
	}
	
	function validators() {
		return $this->validators;
	}
	
	function request($name, $group = false) {
		if (preg_match("/^(.+)\[(.*)\]/U", $name, $match)) {
			$param = $match[1];
			$value = xn($param);
			if ($group) {
				return $value;
			}
			if ($match[2] === " " || $match[2] === "") {
				return $value;
			}
			if (is_array($value) && array_key_exists($match[2], $value)) {
				return $value[$match[2]];
			}
			return null;
		}
		return xn($name);
	}
	
	function _after_parse() {
		parent::_after_parse();
		
		//继承表单设置
		$form = $this->parent("f:form");
		if ($form) {
			$error = $form->attr("error");
			if (is_array($error)) {
				$this->setAttr("error", $error);
			}
		}
		
		//分析Name
		//自动初始化
		$name = $this->attr("name");
		$indexedName = $this->indexedName();
		if ($this->can("redisplay")) {
			$value = $this->attr("value");
			if (is_null($value)) {
				if ($name) {
					$value = $this->request($indexedName);
				}
			}
			else {
				$exec = $this->attr("exec");
				if ($this->can("exec")) {
					if (strstr($value, ":")) {
						list($command, $param) = explode(":", $value, 2);
						if ($command == "expr") {
							$value = $this->_expr($value);
						}
						else if ($command == "json") {
							$value = IJSON::decode($param);
							if (is_array($value)) {
								$json = new IJSON($value);
								$value = $json->__toString();
							}
						}
						else if ($command == "x") {
							$value = xn($param);
						}
						else if ($command == "xn") {
							$value = xn($param);
						}
					}
				}
			}
			if (!is_null($value)) {
				$this->setAttr("value", $value);
			}
		}
		
		//get|post
		if (IRequest::singleton()->isGet() && !if_empty($this->attr("value_get"))) {
			$this->setAttr("value", $this->attr("value_get"));
		}
		elseif (IRequest::singleton()->isPost() && !if_empty($this->attr("value_post"))) {
			$this->setAttr("value", $this->attr("value_post"));
		}
		
		//是否required
		if ($this->attr("required")) {
			$this->validators["__required__"] = array(
				"rule" => "required",
				"params" => array("strict" => true),
				"message" => $this->attr("error.required")
			);
		}
	}
	
	function addError($error) {
		if (!$error) {
			return;
		}
		if (!is_array($error)) {
			$error = array($error);
		}
		$this->errors = array_values(array_merge($this->errors, $error));
	}
	
	function errors() {
		return $this->errors;
	}
	
	function hasErrors() {
		return !empty($this->errors);
	}
	
	function firstError() {
		return $this->hasErrors() ? $this->errors[0] : null;
	}
	
	function renderError() {
		//是否绘制错误信息
		$render = $this->attr("error.render");
		$error = "";
		if ($this->hasErrors() && (is_null($render) || $render)) {
			$layout = $this->attr("layout");
			$this->setAttr("layout", array(
				"tag" => "span",
				"class" => o("@ui.styles.form_error")
			));
			$error = $this->processLayout($this->firstError());
			
			//恢复layout
			$this->attr("layout", $layout);
		}
		if ($error) {
			$error = " " . $error;
		}
		return $error;
	}
	
	function render() {
		//绘制错误时的附加属性
		if ($this->hasErrors()) {
			$class = $this->attr("class");
			$class = $class ? $class . " " . o("@ui.styles.field_error") : o("@ui.styles.field_error");
			$this->setAttr("class", $class);
		}
		return parent::render() . $this->renderError();
	}
	
	function indexedName() {
		if (!is_null($this->indexedName)) {
			return $this->indexedName;
		}
		$name = $this->attr("name");
		$this->indexedName = $name;
		if ($name && preg_match("/^(.+)\[(.*)\]/U", $name, $match) && !$this->groupValue) {
			$name2 = $match[1];
			$index = $match[2];
			if (strlen($index) == 0 || $index === " ") {
				$index = isset(self::$indexes[$name2]) ? self::$indexes[$name2] : 0;
				$name = $name2 . "[" . $index . "]";
				$this->indexedName = $name;
				self::$indexes[$name2] = $index + 1;
			}
			elseif (preg_match("/^\d+$/", $index)) {
				if (!isset(self::$indexes[$name2]) || self::$indexes[$name2] <= $index) {
					self::$indexes[$name2] = $index + 1;
				}
			}
		}
		return $this->indexedName;
	}
	
	/**
	 * 执行校验
	 * 
	 * 从1.1.2开始如果校验规则不是required或notEmpty或equalTo而且值为空的话，该校验规则就会跳过。
	 *
	 * @since 1.1.0
	 */
	function validate() {
		if (!empty($this->validators)) {
			$value = $this->requestValue();
			$validator = new IFormValidator("control", $value);
			$validator->setElement($this);
			if (!$this->form) {
				$this->form = $this->parent("f:form");
			}
			foreach ($this->validators as $_validator) {
				$rule = strtolower($_validator["rule"]);
				if (is_scalar($value) && !in_array($rule, array("required", "notempty", "equalto")) && strlen($value) == 0) {
					continue;
				}
				$message = $this->validateMessage($_validator);
				$validator->apply($_validator["rule"], $_validator["params"], $message);
			}
			$this->addError($validator->errors());
		}
	}
	
	function requestValue() {
		return $this->request($this->indexedName());
	}
	
	function setForm(UIForm $form) {
		$this->form = $form;
	}
	
	function validateMessage($validator) {
		$rule = $validator["rule"];
		$message = $validator["message"];
		$params = $validator["params"];
		if (isset($params["param"])) {
			$params = $params["param"];
		}
		if (!$message) {
			if ($this->form) {
				$messages = $this->form->attr("error.bundle");
				if (is_array($messages)) {
					$msgkey = $this->attr("name") . "." . $rule;
					$message = if_array_get($messages, $msgkey);
				}
			}
			if (!$message) {
				$message = x("~@validator.{$rule}");
			}
		}
		if ($message) {
			if (preg_match("/^~\{(.+)\}$/", $message, $match)) {//本地化
				$message = x("~" . $match[1]);
			}
			//替换变量
			if (strstr($message, "\${")) {
				if (!is_array($params)) {
					$params = array($params);
				}
				foreach ($params as $key=>$value) {
					$message = str_replace("\${{$key}}", $value, $message);
				}
			}
			
			//兼容1.1以前版本
			if (preg_match("/^%\{(.+)\}$/", $message, $match)) {//本地化
				$message = x("~" . $match[1]);
			}
			if (strstr($message, "%{")) {
				if (!is_array($params)) {
					$params = array($params);
				}
				foreach ($params as $key=>$value) {
					$message = str_replace("%{{$key}}", $value, $message);
				}
			}
		}
		return $message;
	}
}

?>